<?php
require_once(dirname(dirname(dirname(__FILE__))) . "/engine/start.php");
$elggMapsFolder = basename(dirname(__FILE__));

/**
 * GLOBAL DEFINES FOR PATHS
 */
define( 'ELGG_MAPS_WEBPATH',$CONFIG->url."mod/".$elggMapsFolder."/" );
define( 'ELGG_MAPS_SYSTEMPATH',$CONFIG->pluginspath.$elggMapsFolder."/" );
define( 'ELGG_MAPS_URL',$CONFIG->url."pg/".$elggMapsFolder."/" );

/**
 * Actions library
 *
 * The code inhere defines the functions used by actions and API methods
 */
 
/**
 * Events that will be triggered on the client
 * These will be sent by emShow
 * as an extra property 'events' in the returned
 * JSON Object
 */
$events = Array();

/**
 * Messagers that will be shown on the client
 * 
 * These will be sent by emShow
 * as an extra property 'log' in the returned
 * JSON Object
 */
$log = Array();

/**
 * Trigger a remote event on the client
 * Events will be sent by emShow as an extra property 'events' in the returned
 * JSON object.
 * @param string $event Event that will be sent to the client
 */
function emTriggerEvent( $event )
{
	global $events;
	$events[] = $event;
	
}
/**
 * Log a message on the client
 * Logged messages be sent by emShow as an extra property 'log' in the returned
 * JSON object.
 * @param string $event Event that will be sent to the client
 */
function emLog($message)
{
	global $log;
	$log[] = $message;
    //emShow( array( 'emError'=> $error ) );
}

/**
 * Returns the ElggObject for a $guid if it's of the 'emMap' subtype
 * or false if it doesn't exist as such.
 * 
 * @param integer $guid The GUID of an emMap
 * @return Mixed The ElggObject or false if an emMap with GUID=$guid does not exist
 */
function emGetMap($guid)
{
	
    $emMap = get_entity($guid);
	
	if (!$emMap || $emMap->getSubtype() != 'emMap') {
		$emMap = false;
	}
	return $emMap;
}

/**
 * Returns the ElggObject for a $guid if it's of the 'emLayer' subtype
 * or false if it doesn't exist as such.
 * 
 * @param integer $guid The GUID of an emLayer
 * @return Mixed The ElggObject or false if the emLayer with GUID=$guid does not exist
 */
function emGetLayer($guid)
{
	
    $emLayer = get_entity($guid);
	
	if (!$emLayer || $emLayer->getSubtype() != 'emLayer') {
		$emLayer = false;
	}
	return $emLayer;
}

Class Map {
	/**
	 * Returns an object with the full emMap metadata
	 * and its layers as 'layers' property
	 * @param integer $guid the guid for an emMap
	 * @return type 
	 */	
	function getInfo($guid)
	{
		if ( ! $emMap = emGetMap( $guid ) ) {
			emLog('Map does not exist');
			return false;
		}
		$emMapData = array();

		// Get basic metadata
		foreach($emMap->getExportableValues() as $name) {
		$emMapData[$name] = $emMap->$name;
		}
		// Get Extended metadata
		foreach(get_metadata_for_entity($guid) as $metadata) {
		$emMapData[$metadata->name] = $emMap->getMetadata($metadata->name);
		}

		$emMapData['layers'] = Map::getLayers($guid);

		return $emMapData;

	}
	/**
	 * Devuelve las capas de un mapa
	 * 
	 * @param integer $guid Map identifier
	 * @return type 
	 */
	function getLayers($guid)
	{
				//Get layers
		$layersObject = elgg_get_entities(array(
			'type'=>'object',
			'subtype'=>'emLayer',
			'container_guid'=>$guid	
		));
		$layers = array();
		foreach($layersObject as $layer)
		{
			$id = $layer->getGUID();
			$layers[$id] = array(
				'title'=>$layer->title,
				'description'=>$layer->description
			);
		}
		return $layers;
	}
	
	/**
	 * Creates a new map and returns it;
	 * By default, an empty layer will created for each
	 * new map
	 * @return ElggObject 
	 */
	function createNew()
	{
		$map = new ElggObject();
		$map->subtype = "emMap";
		$map->access_id = ACCESS_PRIVATE;
		$map->owner_guid = get_loggedin_userid();
		$map->title = "Sin título";

		if ( ! $map->save() ) {
			emLog( "Couldn't create new map");
			return;
		}

		emNewLayer( $map->getGUID() );

		return Map::getInfo( $map->getGUID() );
	}	
}

/**
 * Tries to login a user with the given input.
 * If the user logs in, then the auth.login
 * event is fired on the client
 */
function emLogin()
{
	$wasLoggedIn = isloggedin();
    $username = get_input("username");
    $password = get_input("password");
    $persistent = get_input("persistent", false);
	
    $result = false;
    if (!empty($username) && !empty($password)) {
            if ($user = authenticate($username,$password)) {
                    $result = login($user, $persistent);
            }
}
	//fire auth.login event only if user was not previously logged in
    if ($result && ! $wasLoggedIn) {
        emTriggerEvent("auth.login");
		emTriggerEvent("auth.statusChange");
    	emShow(array());
	//if the user was already logged in, do nothing;
    } elseif ($result && $wasLoggedIn) {
		emShow(array());
    } else {
    	emLog('Unknown user');
        emShow(array());
    }
}
/**
 * Logs a user out.
 * Triggers the "auth.logout" event on the client
 */
function emLogout()
{
	$wasLoggedIn = isloggedin();
	
	$response = logout();
	$output = array( "response"=> $response );
	if ($response &&  $wasLoggedIn ) {
		emTriggerEvent( "auth.logout" );
		emTriggerEvent( "auth.statusChange" );
	}
	emShow($output);
}

/**
 * outputs $stuff to the client
 * If $stuff is an object it gets echoed as JSON. otherwise
 * $stuff is simply echoed.
 * 
 * emShow will also set this properties in the json object
 * - 'events' an array containng the event names that should be fired 
 * on the client.
 * - 'log' an array containg the logged strings.
 * 
 * @param Mixed $stuff  The stuff to print
 */
function emShow( $stuff )
{
	global $events,
			$log;
    if ( gettype($stuff) == 'string' ) {
        echo $stuff;
    } elseif (gettype($stuff) == "array") {
		$stuff = array_merge($stuff, array( "events"=> $events ) );
		$stuff = array_merge($stuff, array( "log"=> $log ) );
        echo json_encode($stuff);
    } else {
		$stuff = Array("response"=> $stuff);
		$stuff = array_merge($stuff, array( "events"=> $events ) );
		$stuff = array_merge($stuff, array( "log"=> $log ) );		
		echo json_encode($stuff);
	}
}

/**
 * Outputs the metadata for the emLayer with guid=$guid
 * @param integer $guid The GUID for an emLayer
 * @return type 
 */
function emShowLayer($guid)
{
	//emRestrictViewAccess($guid);
	$emLayer = emGetLayer( $guid );
	if ( ! $emLayer ) {
		emLog( "Couldn't find layer" );
		return;
	}
	// pages/viewlayer.php expects $entity
	$entity = $emLayer;
	include(ELGG_MAPS_SYSTEMPATH . "pages/viewlayer.php");
	return $emLayer;
}

function emShowVisibleMapsList($userGUID)
{
	$visibleMaps = elgg_get_entities(array(
		'type'=>'object',
		'subtype'=>'emMap',
		'limit'=>'1000'
	));
	
	if (!$visibleMaps) {
		emLog('no_visible_maps');
		return;
	}
	
	$output = elgg_list_entities(array('type' => 'object', 'subtype' => 'emMap', 'limit' => 100, 'full_view' => FALSE));
        emShow($output);
}

function emShowPublicMapsList($userGUID)
{
	$publicMaps = array();
	
	$visibleMaps = elgg_get_entities(array(
		'type'=>'object',
		'subtype'=>'emMap',
		// no anda esto
		//'wheres'=> array('access_id' => ACCESS_PUBLIC)
		'limit'=>'1000'
		
	));
	
	if (!$visibleMaps) {
		emLog('no_visible_maps');
		return;
	}
	// Tengo que hacer este loop porque no puedo 
	// traer solo los access_id==ACCESS_PUBLIC directamente
	// usando la api de Elgg
	foreach($visibleMaps as $map) {
		if ($map->access_id == ACCESS_PUBLIC) {
			$publicMaps[] = $map;	
		}
		
	}
	
	if (!$publicMaps) {
		emLog('no_public_maps');
		return;
	}	
	
	//en lugar de llamar a elgg_list_entities, lo hago a mano como
	// se hace en esa misma funci'on con full_view en TRUE,
	// view_type_toggle en false y pagination en TRUE
	$output = elgg_view_entity_list($publicMaps, count($publicMaps),
			(int) max(get_input('offset', 0), 0),
			(int) max(get_input('limit', 100), 0),
			FALSE,
			FALSE,
			TRUE
	);
//	$output = elgg_list_entities(array(
//		'type' => 'object',
//		'subtype' => 'emMap',
//		'wheres'=>array( 'access_id'=>ACCESS_PUBLIC ) ,
//		'limit' => 100,
//		'full_view' => FALSE
//		
//	));
        emShow($output);
}

function emShowOwnMapsList($userGUID)
{
	$user = get_loggedin_userid();
	if(!$user) {
		emShow("");
		return;
	}
	$visibleMaps = elgg_get_entities(array(
		'type'=>'object',
		'subtype'=>'emMap',
		'limit'=>'1000',
		'owner_guid'=>$user
	));
	
	//ACA ToDo!!! hacer una view que incluya el listado y un lindo lindo boton de NUEVO MAPA
	//$output = elgg_list_entities(array('type' => 'object', 'subtype' => 'emMap', 'limit' => 100, 'full_view' => FALSE));
	$output = "<div style='text-align:right'><button id='emMapNewButton'>Nuevo mapa</button></div>";
	$output .= list_user_objects(get_loggedin_userid(),'emMap', 1000, false);
    emShow($output);
}

function emShowLoginForm()
{
    emShow( elgg_view( "account/forms/login" ) );
}

function emShowSessionInfo()
{
	if ( ! isloggedin() ) {	
		$a = elgg_view( "emMap/logininfo" );
	} else {
		$user = get_loggedin_user();
		$a = elgg_view( "emMap/sessioninfo", array('user'=>$user) );
	}
	
	emShow( $a );
}

function emShowRegisterForm()
{
    $friend_guid = (int) get_input( 'friend_guid', 0 );
    $invitecode = get_input( 'invitecode' );

    // If we're not logged in, display the registration page
    if ( ! isloggedin() ) {
            $output = elgg_view( "account/forms/register", array('friend_guid' => $friend_guid, 'invitecode' => $invitecode) );
            emShow($output);
    // Otherwise, forward to the index page
    }

}

function emShowEditMapForm( $guid )
{
	$emMap = emGetMap( $guid );
	if ( $emMap )  {
		$output = elgg_view( 'emMap/form', array( 'mapData'=> $emMap ) );
	} else {
		$output = elgg_view( 'emMap/form' );
	}
        emShow($output);
}

function emShowMapMetadata($guid)
{
			
	if ($emMap = emGetMap($guid) ) {
		$output = elgg_view('emMap/view', array('entity'=>$emMap));
        emShow($output);
	} 
	
}

/**
 * Erases a map object if current user
 * can edit it.
 *
 * @param {integer} guid The GUID of the emMap Object
 */
function emDeleteMap($guid)
{
	emSoftDeleteMap($guid);
	emShow(array());
}
/**
 * Markas a map object as disabled if current user
 * can edit it.
 *
 * @param {integer} guid The GUID of the emMap Object
 */
function emSoftDeleteMap($guid)
{
	$map = emGetMap($guid);

	if ($map && $map->canEdit()) {
		$map->disable('delete',true);
		emTriggerEvent( "map.deleted" );
	}
}
/**
 * Erases a emMap object with guid
 * gotten from get_input()
 *
 * Devuelve null si no pudo borrar el mapa.
 */
function emDeleteMapAsRequested()
{
	$guid = get_input('mapGUID');
	return emDeleteMap($guid);
}

/**
 * Tries to update an emMap subtype with data
 * that arrives from get_input()
 *
 */
function emUpdateMapAsRequested()
{
	$attributes = array(
		'guid' => get_input('mapGUID'),
		'title' => get_input('title'),
		'description' => get_input('description'),
		'tags' => string_to_tag_array(get_input('tags')),
		'access_id' => (int) get_input('access_id', ACCESS_PRIVATE),
		'extent' => array(
			'left'=>get_input('extentLeft'),
			'bottom'=>get_input('extentBottom'),
			'right'=>get_input('extentRight'),
			'top'=>get_input('extentTop')
		),
		'projection' => get_input('projection'),
		/*
		 * 'features' is an array used by class ElggMap
		 * It's a hidden input that holds data from the 
		 * OpenLayers.Feature.Vector objects that where modified
		 * bye the user.
		 * 'features' may be empty if no feature was
		 * modified on the client even
		 * if there are features on the layers.
		 */
		'features' => get_input('features') ? get_input('features'): array(),
		'delete' => get_input('deleteFeatures') ? get_input('deleteFeatures') : array()
	);
	
	return emUpdateMap($attributes);
}

/**
 * Tries to update an emMap subtype with data
 * that arrives from get_input()
 *
 */
function emUpdateMapAsRequestedFromAjax()
{
	
	$metadata = get_input('mapMetadata');
	
	/**
	 * @todo filtrar data
	 */
	
	$features = get_input('dirtyFeatures');

	$delete = get_input('deletedFeatures');
	
	$attributes = array_merge($metadata, array(
		'tags' => string_to_tag_array($metadata['tags']),
		'access_id' => ((int) $metadata['access_id']) ? (int) $metadata['access_id'] : ACCESS_PRIVATE,		
		'extent' => array(
			'left'=>$metadata['extentLeft'],
			'bottom'=>$metadata['extentBottom'],
			'right'=>$metadata['extentRight'],
			'top'=>$metadata['extentTop']
		),
		'dirtyFeatures' => $features ? $features : array(),
		'deletedFeatures' => $delete ? $delete : array()		
	));
	//die(print_r($attributes,true));
	if ( ! emGetMap($attributes[ "mapGUID" ] ) ) {
		emLog("Couldn't update map");
		return array(); 
	} else {
		return emUpdateMap($attributes['mapGUID'], $attributes);
	}
}

function emNewLayer( $parentMapGUID )
{
	$map = emGetMap($parentMapGUID);
	$layer = new ElggObject();
	$layer->subtype = "emLayer";
	$layer->container_guid = $parentMapGUID;
	$layer->owner_guid = get_loggedin_userid();
	$layer->access_id = $map->access_id;
	$layer->title = "Capa de datos";
	$layer->description = "";
	$layer->is_default = true;
	return $layer->save();
}

/**
 * Updates map with attributes from $params;
 *
 * @param {Object} The entity properties object
 * Properties expected
 * - guid
 * - title
 * - tags
 * - access_id
 * - extent
 * - projection
 * - features (array of features to be deleted.
 * - delete (array of features to be deleted)
 * - array of features to bedeleted
 */
function emUpdateMap($guid, $newProperties)
{
	$return = false;
	//get saved entity
	$mapobject = emGetMap($guid);
	
	if ($mapobject) {
		//set new values
		if (! $mapobject->canEdit() ) {
			return false;
		}
		
		$mapobject->title = $newProperties['title'];
		$mapobject->description = $newProperties['description'];
		$mapobject->tags = $newProperties['tags'];
		$mapobject->extent = $newProperties['extent'];
		$mapobject->projection = $newProperties['projection'];

		// Set access for the map (default to ACCESS_PRIVATE if not provided
		if ($newProperties['access_id'] != $mapobject->access_id) {
			emLog('asd');
			updateAccessId($mapobject, $newProperties['access_id']);
		}
		
		// save to database, no need for GUID retrieval
		$return = $mapobject->save();

		//por el momento solo vamos a tener un layer
		//asi que todo esto se desestima y los features
		//se guardan con el container_guid que tenian...
		//review!!!

		// $layer = new ElggObject();
		// $layer->title = 'Predefinida';
		// $layer->description = 'Capa genérica';
		// $layer->subtype = "emLayer";
		// $layer->container_guid = $newmapGUID;
		// $layer->access_id = $access_id;
		// $layer->owner_guid = get_loggedin_userid();
		// $layer->is_default = true;
		// //desde el mapa llega esto
		// $layer->projection = $projection;
		// //falta el style

		//ahora lo traen los features esto
		//$layerGUID = get_input('layerGUID');

		emUpdateFeatures($newProperties['dirtyFeatures']);

		foreach($newProperties[ 'deletedFeatures' ] as $d) {
			delete_entity($d['guid']);
		}
		
		//return $return;
	}
	return Map::getInfo($mapobject->getGUID());
}

function emUpdateFeatures($newProperties, $projection='EPSG:4326')
{
	if (is_array($newProperties) && !empty($newProperties[0])  ) {
		foreach($newProperties as $np) {
			emUpdateFeatures($np, $projection);
		}
		return;
	}

	if(!empty($newProperties['guid']) ){
		//este es un feature de antes;
		$container = emGetLayer($newProperties['layerGUID']);
		if (!$container) {
			emLog('layer not found');
			return;
		}		
		$feature = get_entity($newProperties['guid']);
		$feature->title = $newProperties['title'];
		$feature->description = $newProperties['description'];
		$feature->access_id = $container->access_id;
		$feature->wkt = $newProperties['wkt'];
		$feature->projection = $projection;
		
	} else {
		$container = emGetLayer($newProperties['layerGUID']);
		if (!$container) {
			emLog('layer not found');
			return;
		}
		$feature = new ElggObject();
		$feature->title = $newProperties['title'];
		$feature->description = $newProperties['description'];	
		$feature->subtype = 'emFeature';
		$feature->container_guid = $container->getGUID();
		$feature->owner_id = get_loggedin_userid();
		$feature->access_id = $container->access_id;
		$feature->wkt = $newProperties['wkt'];
		$feature->projection = $projection;
	}
	$feature->save();
}

	//que fulero esto... una func para re-setear los access id con recursive
	function updateAccessId($entity, $access_id, $recursive = true)
	{
		$entity->access_id = $access_id;
		$entity->save();

		if( ! $recursive ) {
			return;
		}
		$options = array(
			'container_guid'=>$entity->getGUID(),
			'owner_guid'=>$entity->owner_guid,
			'limit'=>1000
		);
		// Get entity children and call this function for each of them;
		$children = elgg_get_entities($options);
		
		foreach($children as $child) {
			updateAccessId($child,$access_id);
		}
	}

?>
